//
// Ishtar C++ Utility Library
//
// Interlocked Amenity - Interlocked State Machine
//

#ifndef __ISHTAR_INTERLOCKED_INTERLOCKED_STATE_MACHINE_H
#define __ISHTAR_INTERLOCKED_INTERLOCKED_STATE_MACHINE_H

#include <Ishtar/Ishtar.h>

#if defined( ISHTAR_COMPILER_HAS_PRAGMA_ONCE )
#pragma once
#endif

#include <Ishtar/Thread/SimpleMutex.h>


namespace Ishtar
{

///////////////////////////////////////////////////////////////////////////////
//
// Interlocked State Machine
//

template< typename Derived, typename StateType, StateType initialState >
class InterlockedStateMachine
{
public:

    InterlockedStateMachine()
        : m_value( initialState )
    {}

    operator StateType() const { return m_value; }


    struct TransitResult
    {
        TransitResult()
            : transited( false )
        {}
        
        TransitResult( Bool transited, StateType value )
            : transited( transited ), value( value )
        {}
        
        operator Bool() const { return transited; }
    
        Bool transited;
        StateType value;  // the value after calling TransitFromTo().
                          // - if transit failed, it is the current value.
                          // - if transit succeeded, it is the new value.
    };

    template< typename EventType >
    TransitResult TransitByEvent()
    {
        typename typedef Derived::TransitRule< EventType > Rule;

        SimpleMutex::UniqueLock ulock( m_mutex );
        return Rule::Apply( m_value );
    }

private:
    
    SimpleMutex m_mutex;
    StateType   m_value;

protected:

    //
    // Transition Routines
    //

    template< StateType source1, StateType target1 >
    struct Transition1
    {
        static TransitResult Apply( StateType& value )
        {
            switch ( value )
            {
            case source1: value = target1; return TransitResult( true, target1 );
            }

            return TransitResult( false, value );
        }
    };

    template< StateType source1, StateType target1,
              StateType source2, StateType target2 >
    struct Transition2
    {
        static TransitResult Apply( StateType& value )
        {
            switch ( value )
            {
            case source1: value = target1; return TransitResult( true, target1 );
            case source2: value = target2; return TransitResult( true, target2 );
            }

            return TransitResult( false, value );
        }
    };

    template< StateType source1, StateType target1,
              StateType source2, StateType target2,
              StateType source3, StateType target3 >
    struct Transition3
    {
        static TransitResult Apply( StateType& value )
        {
            switch ( value )
            {
            case source1: value = target1; return TransitResult( true, target1 );
            case source2: value = target2; return TransitResult( true, target2 );
            case source3: value = target3; return TransitResutl( true, target3 );
            }

            return TransitResult( false, value );
        }
    };

    template< StateType source1, StateType target1,
              StateType source2, StateType target2,
              StateType source3, StateType target3,
              StateType source4, StateType target4 >
    struct Transition4
    {
        static TransitResult Apply( StateType& value )
        {
            switch ( value )
            {
            case source1: value = target1; return TransitResult( true, target1 );
            case source2: value = target2; return TransitResult( true, target2 );
            case source3: value = target3; return TransitResutl( true, target3 );
            case source4: value = target4; return TransitResutl( true, target4 );
            }

            return TransitResult( false, value );
        }
    };
};


///////////////////////////////////////////////////////////////////////////////

} // namespace Ishtar

#endif // __ISHTAR_INTERLOCKED_INTERLOCKED_STATE_MACHINE_H
